package de.farbstreich.tozen2.common;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import de.farbstreich.tozen2.common.TozenProtocolMessage.game;
import de.farbstreich.tozen2.common.TozenProtocolMessage.gameType;
import de.farbstreich.tozen2.common.TozenProtocolMessage.player;

/**
 * This class holds all methods used for decoding the 
 * information from the JSON format into an instance
 * of TozenProtocolMessage.
 * 
 * @author Tim Babies
 *
 */

public class TozenProtocolDecoder {
	private TozenProtocolMessage t;
	private JSONObject obj;
	/**	
	 * This is the standard constructor for this class
	 * @param t
	 * @param obj
	 * 
	 */
	public TozenProtocolDecoder(TozenProtocolMessage t,JSONObject obj){
		this.t = t;
		this.obj = obj;
		
	}
	/**
	 * This Method scans the input and forwards it to the correct
	 * decoding Method.
	 * @return
	 */
	public TozenProtocolMessage decode(){
		//System.out.println("Decoding...");
		
		
		try {
			switch (TozenMessageType.valueOf((String) obj.get("type"))) {
			case SET_NAME:
				decodeSetName(obj);
				break;
			case LOGOUT:
				decodeLogout(obj);
				break;

			case GAMES:
				decodeGames(obj);
				break;
			
			case GAME_TYPES:
				decodeGameTypes(obj);
				break;
			case SET_GAME:
				decodeSetGame(obj);
				break;
			case PLAYERS:
				decodePlayers(obj);
				break;
			case START_GAME:
				decodeStartGame(obj);
				break;
			case GAME:
				decodeGame(obj);
				break;
			case POSITIONS:
				decodePositions(obj);
				break;
			case CURRENT_PLAYER:
				decodeCurrentPlayer(obj);
				break;
			case TEST_MOVE:
				decodeTestMove(obj);
				break;
			case SURRENDER_GAME:
				decodeSurrenderGame(obj);
				break;
			case END_GAME:
				decodeEndGame(obj);
				break;
			case MESSAGE:
				decodeMessage(obj);
				break;
			case PING:
				decodePing(obj);
				break;
			case JOIN_GAME:
				decodeJoinGame(obj);
				break;

			}
		} catch (IllegalArgumentException e) {
			System.out
					.println("Dies ist ein unbekannter Typ. Warte auf nächste Message...");
		}
		
		

		
		return t;
	}
	/**
	 * Decodes a message with the TozenMessageType JOIN_GAME
	 *  
	 * @param obj1 JSONObject
	 *            
	 */
	private void decodeJoinGame(JSONObject obj1){
		t.type = TozenMessageType.JOIN_GAME;
		t.games = new game[1];
		t.games[0] = t.new game();
		t.games[0].id = (int) Math.round((Long) obj1.get("gameId"));
	}

	/**
	 * Decodes a message with the TozenMessageType SET_NAME
	 *  
	 * @param obj1 JSONObject
	 *            
	 */
	private void decodeSetName(JSONObject obj1){
		t.type = TozenMessageType.SET_NAME;
		player p = t.new player();
		p.name = (String) obj1.get("playerName");
		if(obj1.containsKey("playerId"))
			p.id = (int) Math.round((Long) obj1.get("playerId"));
		t.players.add(p);

	}
	
	/**
	 * Decodes a message with the TozenMessageType LOGOUT
	 *  
	 * @param obj1 JSONObject
	 *            
	 */
	private void decodeLogout(JSONObject obj1) {
		t.type = TozenMessageType.LOGOUT;

	}
	/**
	 * Decodes a message with the TozenMessageType GAMES
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeGames(JSONObject obj1) {
		t.type = TozenMessageType.GAMES;
		t.games = new game[(int) Math.round((Long) obj1.get("games"))];
		JSONArray array = (JSONArray) obj1.get("gamesList");
		for (int i = 0; i < t.games.length; i++) {
			JSONObject obj2 = (JSONObject) array.get(i);
			t.games[i] = t.new game();
			t.games[i].title = (String) obj2.get("gameTitle");
			t.games[i].id = (int) Math.round((Long) obj2.get("gameId"));
			t.games[i].name = (String) obj2.get("gameName");
			t.games[i].maxPlayersCount = (int) Math.round((Long) obj2
					.get("maxPlayersCount"));
			t.games[i].playersCount = (int) Math.round((Long) obj2
					.get("playersCount"));
			JSONObject obj6 = (JSONObject) obj1.get("options");
			//t.games[i].options = (HashMap) obj6;
		}
	}

	/**
	 * Decodes a message with the TozenMessageType GAME_TYPES
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeGameTypes(JSONObject obj1) {
		t.type = TozenMessageType.GAME_TYPES;
		t.gameTypes = new gameType[(int) Math.round((Long) obj1.get("gameTypes"))];
		JSONArray array = (JSONArray) obj1.get("gameTypesList");
		try {
			for (int i = 0; i < t.gameTypes.length; i++) {
				JSONObject obj2 = (JSONObject) array.get(i);
				t.gameTypes[i] = t.new gameType();
				t.gameTypes[i].id = (int) Math.round((Long) obj2.get("typeId"));
				t.gameTypes[i].title = (String) obj2.get("gameTitle");
				t.gameTypes[i].maxPlayersCount = (int) Math.round((Long) obj2
						.get("maxPlayersCount"));
				t.gameTypes[i].minPlayersCount = (int) Math.round((Long) obj2
						.get("minPlayersCount"));
				//t.gameTypes[i].options = (HashMap) obj2.get("options");
			}
		} catch (Exception e) {
			System.out.println("Fehler: " +e);
			e.printStackTrace();
		}

	}
	/**
	 * Decodes a message with the TozenMessageType SET_GAME
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeSetGame(JSONObject obj1) {
		t.type = TozenMessageType.SET_GAME;
		t.games = new game[1];
		JSONArray array = (JSONArray) obj1.get("setGame");
		t.games[0] = t.new game();
		t.games[0].id = (int) Math.round((Long) array.get(0));
		t.games[0].name = (String) array.get(1);
		//JSONObject obj2 = (JSONObject) obj1.get("options");
		//t.games[0].options = (HashMap) obj2;

	}
	/**
	 * Decodes a message with the TozenMessageType PLAYERS
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodePlayers(JSONObject obj1) {
		t.type = TozenMessageType.PLAYERS;
		JSONArray array = (JSONArray) obj1.get("playersList");
		for (int i = 0; i < array.size(); i++) {
			JSONObject obj2 = (JSONObject) array.get(i);
			player p = t.new player();
			p.id = (int) Math.round((Long) obj2.get("playerId"));
			p.name = (String) obj2.get("playerName");
			p.ingame = (Boolean) obj2.get("ingame");
			t.players.add(p);
		}
		
	}
	/**
	 * Decodes a message with the TozenMessageType START_GAME
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeStartGame(JSONObject obj1) {
		t.type = TozenMessageType.START_GAME;
	}

	/**
	 * Decodes a message with the TozenMessageType GAME
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeGame(JSONObject obj1) {
		t.type = TozenMessageType.GAME;
		t.games = new game[1];
		t.games[0] = t.new game();
		t.games[0] = t.new game();
		t.games[0].id = (int) Math.round((Long) obj1.get("gameId"));
		t.games[0].title = (String) obj1.get("gameTitle");
		t.games[0].name = (String) obj1.get("gameName");
		t.games[0].minPlayersCount = (int) Math.round((Long) obj1.get("minPlayersCount"));

		JSONArray playersList = (JSONArray) obj1.get("playersList");
		for (Object jo:  playersList) {
			JSONObject o = (JSONObject) jo;
			t.games[0].players.add(
					t.new player(
					((Number)o.get("id")).intValue(), 
					o.get("name").toString(),
					((Number)o.get("color")).intValue()));
		}

		JSONArray positionsList = (JSONArray) obj1.get("positionsList");
		for (Object jo:  positionsList) {
			JSONObject o = (JSONObject) jo;
			t.games[0].positions.add(t.new position(
					((Number)o.get("x")).intValue(),
					((Number)o.get("y")).intValue(),
					((Number)o.get("playerId")).intValue(),
					((Number)o.get("tileId")).intValue()));
		}

	}
	/**
	 * Decodes a message with the TozenMessageType POSITIONS
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodePositions(JSONObject obj1) {
		t.type = TozenMessageType.POSITIONS;
		t.games = new game[1];
		t.games[0] = t.new game();
		
		JSONArray positionsList = (JSONArray) obj1.get("positionsList");
		for (Object jo:  positionsList) {
			JSONObject o = (JSONObject) jo;
			t.games[0].positions.add(t.new position(
					((Number)o.get("x")).intValue(),
					((Number)o.get("y")).intValue(),
					((Number)o.get("playerId")).intValue(),
					((Number)o.get("tileId")).intValue()));
		}

	}
	/**
	 * Decodes a message with the TozenMessageType CURRENT_PLAYER
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeCurrentPlayer(JSONObject obj1) {
		t.type = TozenMessageType.CURRENT_PLAYER;
		player p = t.new player();
		p.id = (int) Math.round((Long) obj1.get("currentPlayer"));
		t.players.add(p);
	}
	/**
	 * Decodes a message with the TozenMessageType TEST_MOVE
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeTestMove(JSONObject obj1) {
		t.type = TozenMessageType.TEST_MOVE;
		t.startX = (int) Math.round((Long) obj1.get("startX"));
		t.startY = (int) Math.round((Long) obj1.get("startY"));
		t.targetX = (int) Math.round((Long) obj1.get("targetX"));
		t.targetY = (int) Math.round((Long) obj1.get("targetY"));

	}
	/**
	 * Decodes a message with the TozenMessageType SURRENDER_GAME
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeSurrenderGame(JSONObject obj1) {
		t.type = TozenMessageType.SURRENDER_GAME;
		player p = t.new player();
		t.players.add(p);
	}
	/**
	 * Decodes a message with the TozenMessageType END_GAME
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeEndGame(JSONObject obj1) {
		t.type = TozenMessageType.END_GAME;
	}
	/**
	 * Decodes a message with the TozenMessageType MESSAGE
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodeMessage(JSONObject obj1) {
		t.type = TozenMessageType.MESSAGE;
		JSONArray array = (JSONArray) obj1.get("messageoptions");
		player p = t.new player();
		p.id = (int) Math.round((Long) array.get(0));
		t.players.add(p);
		t.message = (String) array.get(1);
		t.broadcast = (Boolean) array.get(2);
	}
	/**
	 * Decodes a message with the TozenMessageType PING
	 * 
	 * @param obj1 JSONObject 
	 */
	private void decodePing(JSONObject obj1) {
		t.type = TozenMessageType.PING;
	}

}
